/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include <common/JsonHelper.h>
#include <thread>
#include <algorithm>
#include "json/json.h"
#include "log/Log.h"
#include "protect_engines/hcs/common/HcsHttpStatus.h"
#include "protect_engines/hcs/utils/StorageMgr.h"
#include "config_reader/ConfigIniReader.h"
#include "common/utils/Utils.h"
#include "HcsResourceAccess.h"

using OpenStackPlugin::ServerDetail;
using OpenStackPlugin::GetProjectServersRequest;
using OpenStackPlugin::GetProjectServersResponse;


namespace {
const string MODULE_NAME = "HcsResourceAccess";
const std::string VOLUME_STATUS_IN_USE = "in-use";
const std::string QUERY_MARKER = "marker";
const int32_t CHECK_HCS_NETWORK_FAILED = 1677930259;
const int32_t CHECK_VDC_CONNECT_FAILED = 1577210066;
const int32_t CHECK_HCS_CERT_ERROR = 1677931024;
const int32_t CHECK_HCS_CONNECT_PARAM_ERROR = 1677929220;
const int32_t VDC_PAGE_LIMIT = 100;
const int32_t VDC_PAGE_START = 0;
const int32_t EXEC_CHECK_TIME = 3;
const int32_t QUERY_SERVERS_OFFSET = 1;
const std::string STORAGE_TYPE_CENTRALIZED = "0";
const std::string STORAGE_TYPE_DISTRIBUTED = "1";
const std::string ERRCODE_VBS_COMMAND_ERR = "50510012";
}

namespace HcsPlugin {
HcsResourceAccess::HcsResourceAccess(ApplicationEnvironment appEnv)
    : m_appEnv(appEnv)
{
    m_hcsOpServiceUtils.GetAppEnv(m_appEnv);
}

HcsResourceAccess::HcsResourceAccess(ApplicationEnvironment appEnv, Application application)
    : m_appEnv(appEnv), m_application(application)
{
    m_hcsOpServiceUtils.GetAppEnv(m_appEnv);
}

HcsResourceAccess::HcsResourceAccess(ApplicationEnvironment appEnv, QueryByPage pageInfo) : m_appEnv(appEnv),
    m_condition(pageInfo)
{
    m_hcsOpServiceUtils.GetAppEnv(m_appEnv);
}

HcsResourceAccess::HcsResourceAccess(ApplicationEnvironment appEnv, Application application,
    QueryByPage pageInfo)
    : m_appEnv(appEnv), m_application(application), m_condition(pageInfo)
{
    m_hcsOpServiceUtils.GetAppEnv(m_appEnv);
}

HcsResourceAccess::~HcsResourceAccess()
{}

void HcsResourceAccess::SetApplication(Application application)
{
    DBGLOG("%s", application.id.c_str());
    m_application = application;
}

int32_t HcsResourceAccess::GetVirtualMachineDetailInfo(
    ResourceResultByPage &returnValue, const std::vector<std::string> &vmLists)
{
    for (const auto &id : vmLists) {
        ApplicationResource vmDetailInfo;
        // 根据项目的token查询指定虚拟机的详细信息
        std::vector<std::string> diskIds;
        HostResource hostResource;
        hostResource.m_id = id;
        if (GetSpcifiedVmInfo(vmDetailInfo, hostResource, diskIds) != SUCCESS) {
            ERRLOG("Failed to get spcified vm info. vmId: %s", id.c_str());
            return FAILED;
        }
        // 查询diskInfo
        std::string hostExtendInfoStr;
        if (GetDisksDetailInfo(hostExtendInfoStr, hostResource, diskIds, vmDetailInfo) != SUCCESS) {
            ERRLOG("Failed to get disks vm info.");
            return FAILED;
        }
        vmDetailInfo.__set_type("CloudHost");
        vmDetailInfo.__set_subType("HCSCloudHost");
        vmDetailInfo.__set_parentId(m_application.id);
        vmDetailInfo.__set_parentName(m_application.name);
        vmDetailInfo.__set_id(vmDetailInfo.id);
        vmDetailInfo.__set_name(vmDetailInfo.name);
        vmDetailInfo.__set_extendInfo(hostExtendInfoStr);
        returnValue.items.push_back(vmDetailInfo);
    }
    returnValue.__set_total(returnValue.items.size());
    DBGLOG("Get VirtualMachine detail info success.");
    return SUCCESS;
}

int32_t HcsResourceAccess::GetDisksDetailInfo(std::string &hostExtendInfoStr, HostResource &hostResource,
    const std::vector<std::string> &diskIds, const ApplicationResource &vmDetailInfo)
{
    ResourceProjectExtendInfo projectBriefInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectBriefInfo)) {
        ERRLOG("Failed to parse protect brief info failed.");
        return FAILED;
    }
    for (const auto &id : diskIds) {
        DiskInfo diskInfo;
        if (GetSpcifiedEVSDisk(diskInfo, id) != SUCCESS) {
            ERRLOG("Failed to query disk info. diskId: %s", id.c_str());
            return FAILED;
        }
        if (diskInfo.m_shareable) {
            DBGLOG("This is shared disk.");
            continue;
        }
        hostResource.m_diskInfo.push_back(diskInfo);
    }
    hostResource.m_id = vmDetailInfo.id;
    hostResource.m_name = vmDetailInfo.name;
    hostResource.m_regionId = projectBriefInfo.m_regionId;
    hostResource.m_projectId = projectBriefInfo.m_projectId;
    HostExtendInfo hostExtendInfo;
    if (!Module::JsonHelper::StructToJsonString(hostResource, hostExtendInfo.m_hostResource)) {
        ERRLOG("HostResource format conversion failed.");
        return FAILED;
    }
    if (!Module::JsonHelper::StructToJsonString(hostExtendInfo, hostExtendInfoStr)) {
        ERRLOG("Host info format conversion failed.");
        return FAILED;
    }
    DBGLOG("Get disk detail info success.");
    return SUCCESS;
}

int32_t HcsResourceAccess::CheckAppConnect(ActionResult &returnValue)
{
    GetTokenRequest request;
    if (CheckConnectionParams(request, returnValue) != SUCCESS) {
        ERRLOG("Check vdc connect failed.");
        returnValue.__set_bodyErr(CHECK_VDC_CONNECT_FAILED);
        returnValue.__set_code(CHECK_VDC_CONNECT_FAILED);
        returnValue.__set_message("Check vdc connect failed.");
        return FAILED;
    }
    
    IamClient iamClient;
    std::shared_ptr<GetTokenResponse> response;
    if (m_hcsOpServiceUtils.GetIsOpServiceEnv()) {
        response = iamClient.VerifyToken(request);
    } else {
        response = iamClient.GetToken(request);
    }
    if (response == nullptr) {
        ERRLOG("Check hcs connect failed.");
        returnValue.__set_code(CHECK_HCS_NETWORK_FAILED);
        returnValue.__set_bodyErr(CHECK_HCS_NETWORK_FAILED);
        returnValue.__set_message("Check hcs connect failed.");
        return FAILED;
    }
    if (response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::CREATEED) &&
        response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        // 判断是否为证书错误导致DTS2022101103600
        if (CertErrorCode.find(response->GetErrCode()) != CertErrorCode.end()) {
            ERRLOG("Check hcs cert failed.");
            returnValue.__set_code(CHECK_HCS_CERT_ERROR);
            returnValue.__set_bodyErr(CHECK_HCS_CERT_ERROR);
            returnValue.__set_message("Check hcs cert failed.");
        } else if (response->GetStatusCode() == static_cast<uint32_t>(HcsExternalStatusCode::UNAUTHORIZED)) {
            ERRLOG("Username or password is invalid.");
            returnValue.__set_code(CHCEK_USER_FAILED);
            returnValue.__set_bodyErr(CHCEK_USER_FAILED);
            returnValue.__set_message("Username or password is invalid.");
        } else {
            ERRLOG("Check hcs connect failed.");
            returnValue.__set_code(CHECK_HCS_NETWORK_FAILED);
            returnValue.__set_bodyErr(CHECK_HCS_NETWORK_FAILED);
            returnValue.__set_message("Check hcs connect failed.");
        }
        ERRLOG("Response failed, errorCode:%d errorStr:%s statusCode:%d", response->GetErrCode(),
            response->GetErrString().c_str(), response->GetStatusCode());
        return FAILED;
    }
    returnValue.__set_code(0);
    DBGLOG("Check application connect success.");
    return SUCCESS;
}

int32_t HcsResourceAccess::CheckIfVdcSrvMgr(const std::string &domainName)
{
    ResourceExtendInfoVdcs vdcInfo;
    vdcInfo.m_domainName = domainName;
    vdcInfo.m_name = m_application.auth.authkey;
    vdcInfo.m_passwd = m_application.auth.authPwd;
    UserDetail userObj;
    if (!GetvdcUserDetail(vdcInfo, userObj, false)) {
        WARNLOG("Get user(%s) detail failed, check if deleted.", vdcInfo.m_name.c_str());
        return FAILED;
    }
    std::string userRole = Module::ConfigReader::getString("HcsConfig", "VdcUserRole");
    for (const auto &role : userObj.m_user.m_roleList) {
        if (role.m_name == userRole) {
            INFOLOG("User(%s) role(%s).", vdcInfo.m_name.c_str(), role.m_name.c_str());
            return SUCCESS;
        }
        WARNLOG("User(%s) role(%s).", vdcInfo.m_name.c_str(), role.m_name.c_str());
    }
    // 取消vdc用户管理员角色的强要求，非管理员用户也可注册
    return SUCCESS;
}

int32_t HcsResourceAccess::CheckConnectionParams(GetTokenRequest &request, ActionResult &returnValue)
{
    Json::Reader domainInfoReader;
    Json::Value domainInfoJson;
    if (!domainInfoReader.parse(m_application.extendInfo, domainInfoJson)) {
        ERRLOG("Failed to read extendInfo.");
        return FAILED;
    }

    AuthObj auth;
    auth.name = m_application.auth.authkey;
    auth.passwd = m_application.auth.authPwd;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetEndpoint(m_appEnv.endpoint);
    // 运营管理员 "mo_bss_admin"   or   租户name
    if (!domainInfoJson.isMember("domain")) {
        ERRLOG("Task params is error.");
        return FAILED;
    }
    std::string sourceDomain = domainInfoJson["domain"].asString();
    request.SetDomain(sourceDomain);
    request.SetScopeValue(sourceDomain);
    request.SetToken(m_hcsOpServiceUtils.GetToken());
    request.SetExtendInfo(m_application.extendInfo);
    if (domainInfoJson.isMember("isVdc") && CheckIfVdcSrvMgr(sourceDomain) != SUCCESS) {
        returnValue.__set_code(CHECK_VDC_CONNECT_FAILED);
        returnValue.__set_bodyErr(CHECK_VDC_CONNECT_FAILED);
        return FAILED;
    }
    return SUCCESS;
}

int32_t HcsResourceAccess::GetTenantInfo(ResourceResultByPage &page)
{
    QueryVdcListRequest request;
    AuthObj auth;
    auth.name = m_appEnv.auth.authkey;
    auth.passwd = m_appEnv.auth.authPwd;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetScopeValue("mo_bss_admin");
    request.SetDomain("mo_bss_admin");
    request.SetEndpoint(m_appEnv.endpoint);
    request.SetLimit(m_condition.pageSize);
    request.SetUpperVdcId("0");
    request.SetStart(m_condition.pageSize * m_condition.pageNo);
    request.SetNeedRetry(false);

    ScClient scClient;
    std::shared_ptr<QueryVdcListResponse> response = scClient.QueryVdcList(request);
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return FAILED;
    }
    std::vector<ApplicationResource> applicationResources;
    if (!AssemblyTenantInfo(applicationResources, response)) {
        ERRLOG("Failed to assembly tenant info.");
        return FAILED;
    }
    page.__set_items(applicationResources);
    DBGLOG("Get tenant info success.");
    return SUCCESS;
}

bool HcsResourceAccess::AssemblyTenantInfo(
    std::vector<ApplicationResource> &applicationResources, const std::shared_ptr<QueryVdcListResponse> &response)
{
    if (response.get() == nullptr) {
        ERRLOG("Response instance is null.");
        return false;
    }
    VdcListDetail vdcList = response->GetVdcListDetail();
    for (const auto &it : vdcList.m_vdcs) {
        ApplicationResource returnValue;
        returnValue.__set_type("Tenant");
        returnValue.__set_subType("HCSTenant");
        returnValue.__set_id(it.m_domainId);
        returnValue.__set_name(it.m_domainName);
        returnValue.__set_parentId("");
        returnValue.__set_parentName("");
        //  这里不上报 parentId parentName
        ResourceVdcInfo resourceVdcInfo;
        resourceVdcInfo.m_id = it.m_id;
        resourceVdcInfo.m_name = it.m_name;
        resourceVdcInfo.m_domainId = it.m_domainId;
        resourceVdcInfo.m_domainName = it.m_domainName;
        std::string resourceVdcInfoStr;
        if (!Module::JsonHelper::StructToJsonString(resourceVdcInfo, resourceVdcInfoStr)) {
            ERRLOG("ResourceVdcInfo format conversion failed.");
            return false;
        }
        returnValue.__set_extendInfo(resourceVdcInfoStr);
        applicationResources.push_back(returnValue);
    }
    return true;
}

int32_t HcsResourceAccess::GetVDCResourceList(ResourceResultByPage& page,
    std::vector<std::string>& errorUserName, std::string &parentId)
{
    std::vector<ResourceExtendInfoVdcs> topVdcs;
    std::vector<ResourceExtendInfoVdcs> missVdc;
    int getTopRet = GetTopLevelVdcs(topVdcs, missVdc, parentId); // 感知获取VDC列表 存在、部分存在、都不存在
    if (getTopRet == FAILED && missVdc.size() == 0) {
        ERRLOG("Failed to get top vdcs.");
        return FAILED;
    }
    for (const auto& miss : missVdc) {
        errorUserName.push_back(miss.m_name);
        WARNLOG("Vdc %s missed.", miss.m_name.c_str());
    }
    for (auto &vdc : topVdcs) {
        ApplicationResource returnValue;
        std::string vdcStr;
        if (!Module::JsonHelper::StructToJsonString(vdc, vdcStr)) {
            ERRLOG("Convert VDC info to json string failed.");
            return FAILED;
        }
        returnValue.__set_type("VDC");
        returnValue.__set_subType("HCSVDC");
        returnValue.__set_id(vdc.m_id);
        returnValue.__set_name(vdc.m_vdcName);
        returnValue.__set_parentId(vdc.m_domainId);    // 租户ID
        returnValue.__set_parentName(vdc.m_domainName);    // 租户名称
        returnValue.__set_extendInfo(vdcStr);
        page.items.push_back(returnValue);
    }
    page.__set_total(page.items.size());
    DBGLOG("Get VDC list success.");
    return getTopRet;
}

int32_t HcsResourceAccess::GetProjectLists(ResourceResultByPage &page, std::string &parentId, std::string &erroParam)
{
    ResourceExtendInfoVdcs curVdc;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, curVdc)) {
        ERRLOG("Convert VDC info to json string failed.");
        return FAILED;
    }
    erroParam = curVdc.m_name;
    QueryResourceListRequest request;
    GetResourceListRequest(request, curVdc);
    request.SetStart(m_condition.pageNo * m_condition.pageSize);
    request.SetLimit(m_condition.pageSize);
    ScClient scClient;
    std::shared_ptr<QueryResourceListResponse> response = scClient.QueryResourceList(request);
    if (response == nullptr || response->GetHttpStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        parentId = curVdc.m_id;
        return FAILED;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return FAILED;
    }
    // 查询工程详细信息
    ResourceListDetail resourceListDetail = response->GetResourceListDetail();
    for (const auto &it : resourceListDetail.m_projects) {
        ApplicationResource returnValue;
        if (GetSpcifiedProject(returnValue, it.m_id, curVdc) != SUCCESS) {
            ERRLOG("Failed to get project lists");
            continue;
        }
        page.items.push_back(returnValue);
    }
    page.__set_total(page.items.size());
    DBGLOG("Get project list success.");
    return SUCCESS;
}

void HcsResourceAccess::GetResourceListRequest(QueryResourceListRequest& request,
    const ResourceExtendInfoVdcs& vdcinfo)
{
    AuthObj auth;
    auth.name = vdcinfo.m_name;
    auth.passwd = vdcinfo.m_passwd;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetVdcManagerId(vdcinfo.m_id);
    request.SetDomain(vdcinfo.m_domainName);
    request.SetScopeValue(vdcinfo.m_domainName);
    request.SetEndpoint(m_appEnv.endpoint);
    request.SetQueryAllProject(true);
}

int32_t HcsResourceAccess::GetSpcifiedProject(
    ApplicationResource &returnValue, const std::string &projectId, const ResourceExtendInfoVdcs &vdcInfo)
{
    AuthObj auth;
    auth.name = vdcInfo.m_name;
    auth.passwd = vdcInfo.m_passwd;
    QueryProjectDetailRequest request;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(vdcInfo.m_domainName);
    request.SetScopeValue(vdcInfo.m_domainName);
    request.SetProjectId(projectId);
    request.SetEndpoint(m_appEnv.endpoint);
    ScClient scClient;
    std::shared_ptr<QueryProjectDetailResponse> response = scClient.QueryProjectDetail(request);
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return FAILED;
    }
    ProjectDetail projectDetail = response->GetProjectDetail();
    // 赋值
    std::string extendInfoStr;
    projectDetail.m_projectDetailInfo.m_tenantId = vdcInfo.m_domainId; // 修改VDC ID为PM下发的租户ID, 否则PM无法建立vdc与项目的映射关系
    if (!AssemblyProjectInfo(extendInfoStr, projectDetail, vdcInfo)) {
        ERRLOG("Failed to assembly project info.");
        return FAILED;
    }
    returnValue.__set_type("Project");
    returnValue.__set_subType("HCSProject");
    returnValue.__set_id(projectDetail.m_projectDetailInfo.m_id);
    returnValue.__set_name(projectDetail.m_projectDetailInfo.m_name);
    returnValue.__set_parentId(vdcInfo.m_domainId);
    returnValue.__set_parentName(vdcInfo.m_domainName);
    returnValue.__set_extendInfo(extendInfoStr);
    DBGLOG("Get spcified project success.");
    return SUCCESS;
}

bool HcsResourceAccess::AssemblyProjectInfo(
    std::string &projectInfo, const ProjectDetail &projectDetail, const ResourceExtendInfoVdcs &vdcInfo)
{
    ProjectResource projectResource(projectDetail, vdcInfo);
    ProjectExtendInfo projectExtendInfo;
    if (!Module::JsonHelper::StructToJsonString(projectResource, projectExtendInfo.m_projectResource)) {
        ERRLOG("ProjectResource format conversion failed.");
        return false;
    }
    projectExtendInfo.m_userName = vdcInfo.m_userName;
    if (!Module::JsonHelper::StructToJsonString(projectExtendInfo, projectInfo)) {
        ERRLOG("ProjectExtendInfo format conversion failed.");
        return false;
    }
    return true;
}

int32_t HcsResourceAccess::GetTopLevelVdcs(std::vector<ResourceExtendInfoVdcs> &topVdc,
    std::vector<ResourceExtendInfoVdcs>& missVdc, std::string &parentId)
{
    // 查询指定租户下面的所有vdc列表
    VdcListDetail vdcList;
    if (!GetVdcsInfoUnderTenantByScApi(vdcList, parentId)) {
        ERRLOG("Failed to get vdc info under tenant.");
        return FAILED;
    }
    // 解析任务参数中每个用户对应的各自的VDC信息
    TaskVdcList taskVdcList;
    if (!GetVdcsInfoFromTaskParams(taskVdcList)) {
        ERRLOG("Failed to parse vdc info from task params.");
        return FAILED;
    }
    // 筛选出有效的最高级vdc用户
    int filterRet = FilterTopLevelVdc(missVdc, topVdc, vdcList, taskVdcList);
    if (filterRet == FAILED) {
        ERRLOG("Failed to get highest vdc info.");
        return FAILED;
    }
    DBGLOG("Get top level vdcs success.");
    return filterRet;
}

bool HcsResourceAccess::GetVdcsInfoUnderTenantByScApi(VdcListDetail &vdcList, std::string &parentId, bool needTry)
{
    Json::Reader extendInfoReader;
    Json::Value extendInfoJson;
    if (!extendInfoReader.parse(m_application.extendInfo, extendInfoJson)) {
        ERRLOG("Failed to read extendInfo.");
        return false;
    }
    AuthObj auth;
    QueryVdcListRequest vdcListRequest;
    if (!GetVdcsExtendInfoParams(auth, vdcListRequest, extendInfoJson)) {
        ERRLOG("Get vdcs extend info params failed.");
        return false;
    }
    vdcListRequest.SetUserInfo(auth);
    vdcListRequest.SetScopeValue("mo_bss_admin");
    vdcListRequest.SetDomain("mo_bss_admin");
    vdcListRequest.SetEnvAddress(m_appEnv.id);
    vdcListRequest.SetEndpoint(m_appEnv.endpoint);
    vdcListRequest.SetNeedRetry(needTry);
    
    if (!extendInfoJson.isMember("domainId")) {
        ERRLOG("Task params is error.");
        return false;
    }
    vdcListRequest.SetDomainId(extendInfoJson["domainId"].asString());
    parentId = extendInfoJson["domainId"].asString();

    ScClient scClient;
    std::shared_ptr<QueryVdcListResponse> response = scClient.QueryVdcList(vdcListRequest);
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return false;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return false;
    }
    vdcList = response->GetVdcListDetail();
    DBGLOG("Get vdcs info under tenant success.");
    return true;
}

bool HcsResourceAccess::GetVdcsExtendInfoParams(
    AuthObj &auth, QueryVdcListRequest &vdcListRequest, Json::Value &extendInfoJson)
{
    if (extendInfoJson["isVdc"] == "true") {
        Json::Reader authExtendInfoReader;
        Json::Value authExtendInfoJson;
        if (!authExtendInfoReader.parse(m_appEnv.extendInfo, authExtendInfoJson)) {
            ERRLOG("Failed to read extendInfo.");
            return false;
        }

        if (!authExtendInfoJson.isMember("envName") || !authExtendInfoJson.isMember("envPasswd")) {
            ERRLOG("Failed, json extendinfo not have envname or envpasswd.");
            return false;
        }

        auth.name = authExtendInfoJson["envName"].asString();
        auth.passwd = authExtendInfoJson["envPasswd"].asString();
        if (auth.name.empty() || auth.passwd.empty()) {
            ERRLOG("AuthObj extendinfo env name or env password empty.");
            return false;
        }
        vdcListRequest.SetLimit(VDC_PAGE_LIMIT);
        vdcListRequest.SetStart(VDC_PAGE_START);
        if (!extendInfoJson.isMember("domain")) {
            ERRLOG("Task params is error.");
            return false;
        }

        vdcListRequest.SetDomain(extendInfoJson["domain"].asString());
        vdcListRequest.SetScopeValue(extendInfoJson["domain"].asString());
    } else {
        auth.name = m_appEnv.auth.authkey;
        auth.passwd = m_appEnv.auth.authPwd;
        vdcListRequest.SetLimit(m_condition.pageSize);
        vdcListRequest.SetStart(m_condition.pageSize * m_condition.pageNo);
    }
    return true;
}

bool HcsResourceAccess::GetVdcsInfoFromTaskParams(TaskVdcList &taskVdcList)
{
    std::string extendAuthVdcInfo = m_application.auth.extendInfo;
    Json::Reader extendVdcInfoReader;
    Json::Value extendVdcInfoJson;
    if (!extendVdcInfoReader.parse(extendAuthVdcInfo, extendVdcInfoJson)) {
        ERRLOG("Failed to read extendInfo.");
        return false;
    }
    if (!extendVdcInfoJson.isMember("vdcInfos")) {
        ERRLOG("Task params is error.");
        return false;
    }
    std::string vdcInfos = extendVdcInfoJson["vdcInfos"].asString();
    Json::Reader infoReader;
    Json::Value namePassJson;
    if (!infoReader.parse(vdcInfos, namePassJson)) {
        ERRLOG("Failed to trans vdc info form str to json value.");
        return false;
    }
    for (const auto &it : namePassJson) {
        ResourceExtendInfoVdcs resourceExtendInfoVdcs;
        if (it.isMember("name") && it.isMember("passwd")) {
            resourceExtendInfoVdcs.m_name = it["name"].asString();
            resourceExtendInfoVdcs.m_userName = it["name"].asString();
            resourceExtendInfoVdcs.m_passwd = it["passwd"].asString();
            resourceExtendInfoVdcs.m_domainName = m_application.name; // 租户名称
        } else {
            ERRLOG("Task params is error.");
            return false;
        }
        taskVdcList.m_resourceExtendInfoVdcs.push_back(resourceExtendInfoVdcs);
    }
    if (taskVdcList.m_resourceExtendInfoVdcs.size() <= 0) {
        ERRLOG("Task not send vdc info.");
        return false;
    }
    DBGLOG("Get vdcs info from task params success.");
    return true;
}

bool HcsResourceAccess::GetvdcUserDetail(const ResourceExtendInfoVdcs &vdcUser, UserDetail &userDetail, bool retry)
{
    AuthObj auth;
    auth.name = vdcUser.m_name;
    auth.passwd = vdcUser.m_passwd;
    GetVdcUserDetailRequest request;
    request.SetUserName(vdcUser.m_name);
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(vdcUser.m_domainName);
    request.SetScopeValue(vdcUser.m_domainName);
    request.SetEndpoint(m_appEnv.endpoint);
    request.SetNeedRetry(retry);
    request.SetNeedNewToken();
    ScClient scClient;
    std::shared_ptr<GetVdcUserDetailResponse> response = scClient.GetVDCUserDetailInfo(request);
    if (response == nullptr) {
        ERRLOG("Failed to get user detail.");
        return false;
    }
    if (response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed get user detail, status(%d).", response->GetStatusCode());
        return false;
    }

    if (!response->Serial()) {
        ERRLOG("User detail serial failed.");
        return false;
    }
    userDetail = response->GetUserDetail();
    return true;
}

int HcsResourceAccess::FilterTopLevelVdc(std::vector<ResourceExtendInfoVdcs>& missVdc,
    std::vector<ResourceExtendInfoVdcs> &topVdc, VdcListDetail &vdcList, TaskVdcList &taskVdcList)
{
    std::vector<ResourceExtendInfoVdcs> topLevelVdcsInfo;
    UserDetail userObj;
    // taskVdcList:任务下发的VDC；vdcList：当前租户下实际查询的VDC
    for (int i = 0; i < taskVdcList.m_resourceExtendInfoVdcs.size(); i++) {
        ResourceExtendInfoVdcs& curTaskVdcInfo = taskVdcList.m_resourceExtendInfoVdcs[i];
        if (!GetvdcUserDetail(curTaskVdcInfo, userObj, true)) {
            WARNLOG("Get user(%s) detail failed, check if deleted.", curTaskVdcInfo.m_name.c_str());
            missVdc.push_back(curTaskVdcInfo);
            continue;
        }
        bool match = false;
        for (int j = 0; j < vdcList.m_vdcs.size(); j++) {
            const VdcList& curVdcInfo = vdcList.m_vdcs[j];
            if (userObj.m_user.m_vdcId == curVdcInfo.m_id) {
                curTaskVdcInfo.m_id = curVdcInfo.m_id;
                curTaskVdcInfo.m_domainId = curVdcInfo.m_domainId;
                curTaskVdcInfo.m_domainName = curVdcInfo.m_domainName;
                curTaskVdcInfo.m_vdcName = curVdcInfo.m_name;
                curTaskVdcInfo.m_level = curVdcInfo.m_level;
                topLevelVdcsInfo.push_back(curTaskVdcInfo);
                match = true;
                break;
            }
        }
        if (!match) {
            missVdc.push_back(curTaskVdcInfo);
            WARNLOG("User(%s) not match any vdc.", curTaskVdcInfo.m_name.c_str());
        }
    }
    if (topLevelVdcsInfo.empty()) {
        ERRLOG("Compare vdc info between task vdc info and query vdc info failed.");
        return missVdc.empty() ? FAILED : PART_MISS;
    }
    // 筛选有效的vdc用户
    std::vector<ResourceExtendInfoVdcs> topLevelVdcs;
    FilterAvaibleVdc(topLevelVdcsInfo, topLevelVdcs, missVdc);
    if (topLevelVdcs.size() <= 0) {
        ERRLOG("Not found available vdc.");
        return missVdc.empty() ? FAILED : PART_MISS;
    }
    int maxLevel = topLevelVdcs[0].m_level;
    for (int i = 0; i < topLevelVdcs.size(); i++) {
        ResourceExtendInfoVdcs curVdc = topLevelVdcs[i];
        if (curVdc.m_level == maxLevel) {
            topVdc.push_back(curVdc);
        }
    }
    DBGLOG("Filter top level vdc success");
    return missVdc.empty() ? SUCCESS : PART_MISS; // 获取下发的VDC列表 存在、部分存在
}

void HcsResourceAccess::FilterAvaibleVdc(const std::vector <ResourceExtendInfoVdcs> &topLevelVdcsInfo,
                                         std::vector <ResourceExtendInfoVdcs> &topLevelVdcs,
                                         std::vector <ResourceExtendInfoVdcs> &missVdc)
{
    for (const auto &it : topLevelVdcsInfo) {
        IamClient iamClient;
        AuthObj auth;
        auth.name = it.m_name;
        auth.passwd = it.m_passwd;
        GetTokenRequest request;
        request.SetEnvAddress(m_appEnv.id);
        request.SetUserInfo(auth);
        request.SetEndpoint(m_appEnv.endpoint);
        request.SetDomain(m_application.name);  // tenant
        request.SetScopeValue(m_application.name);
        std::shared_ptr<GetTokenResponse> response = iamClient.GetToken(request);
        if (response == nullptr) {
            ERRLOG("Failed to get iam token response.");
            missVdc.push_back(it);
            continue;
        } else if (response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::CREATEED)) {
            ERRLOG("response info, errorCode: %d , errDesc: %s ,statusCode: %d", response->GetErrCode(),
                   response->GetErrString().c_str(), response->GetStatusCode());
            missVdc.push_back(it);
            continue;
        }
        topLevelVdcs.push_back(it);
    }
    // 按照等级升序排序
    std::sort(topLevelVdcs.begin(), topLevelVdcs.end(), [](auto vdcX, auto vdcY)->bool {
        return (vdcX.m_level < vdcY.m_level);
    });
}
int32_t HcsResourceAccess::AssemblyGetServerListRequest(GetProjectServersRequest &request, const AuthObj &auth,
    const ProjectResource &projectResource)
{
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(projectResource.m_resourceVdc.m_domainName);
    request.SetEndpoint(m_appEnv.endpoint);
    Json::Reader conditionReader;
    Json::Value conditionJson;
    if (!conditionReader.parse(m_condition.conditions, conditionJson)) {
        ERRLOG("Failed to read condition.");
        return FAILED;
    }
    if (conditionJson.isMember(QUERY_MARKER)) {
        std::string marker = conditionJson[QUERY_MARKER].asString();
        request.SetServerMarker(marker);
    }
    request.SetServerLimit(m_condition.pageSize);
    ResourceProjectExtendInfo projectExtendInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectExtendInfo)) {
        ERRLOG("Application info format conversion failed.");
        return FAILED;
    }
    request.SetScopeValue(projectExtendInfo.m_projectId);
    request.SetRegion(projectExtendInfo.m_regionId);
    return SUCCESS;
}
int32_t HcsResourceAccess::GetVirtualMachineList(ResourceResultByPage& page, std::string &parentId)
{
    ProjectResource projectResource;
    if (HostExtendInfoParse(projectResource) != SUCCESS) {
        ERRLOG("Parse HostExtendInfo failed.");
        return FAILED;
    }
    AuthObj auth;
    auth.name = projectResource.m_resourceVdc.m_name;
    auth.passwd = projectResource.m_resourceVdc.m_passwd;
    GetProjectServersRequest request;
    if (AssemblyGetServerListRequest(request, auth, projectResource) != SUCCESS) {
        ERRLOG("Failed to assembly the request of get server list");
        return FAILED;
    }
    parentId = request.GetScopeValue();
    HcsNovaClient hcsNovaClient;
    std::shared_ptr<GetProjectServersResponse> response = hcsNovaClient.GetProjectServers(request);
    //  若本次接口调用返回403则将缓存清掉进行重试一次
    if (response != nullptr && response->GetStatusCode() == static_cast<uint32_t>(HcsExternalStatusCode::FORIBDDEN)) {
        HCSTokenMgr::GetInstance().DeleteToken(request);
        INFOLOG("Resend request when the response code is 403");
        response = hcsNovaClient.GetProjectServers(request);
    }
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }

    OpenStackPlugin::ServerList serverListDetail = response->GetProjectServerList();
    for (const auto &it : serverListDetail.m_serverList) {
        ApplicationResource vmDetailInfo;
        if (ComposeVMDetail(vmDetailInfo, it, projectResource.m_resourceVdc.m_name) != SUCCESS) {
            ERRLOG("Failed to compose vm detail.");
            continue;
        }
        page.items.push_back(vmDetailInfo);
    }
    page.__set_total(serverListDetail.m_serverList.size());
    DBGLOG("Get virtual machine list success.");
    return SUCCESS;
}

int32_t HcsResourceAccess::ComposeVMDetail(ApplicationResource& vmDetailInfo, const OpenStackServerInfo& hostInfo,
    const std::string &userName)
{
    ResourceProjectExtendInfo projectBriefInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectBriefInfo)) {
        ERRLOG("Failed to parse protect brief info failed.");
        return FAILED;
    }

    HostResource hostResource;
    hostResource.m_id = hostInfo.m_uuid;
    hostResource.m_name = hostInfo.m_name;
    hostResource.m_projectId = projectBriefInfo.m_projectId;
    hostResource.m_regionId = projectBriefInfo.m_regionId;
    hostResource.m_status = hostInfo.m_metadata.m_softDelete == "true" ? "soft_delete" : hostInfo.m_oSEXTSTSvmState;
    hostResource.m_osType = hostInfo.m_metadata.m_os_type;
    hostResource.m_vmIp = hostInfo.m_addresses;
    hostResource.m_diskInfo.clear();

    HostExtendInfo hostExtendInfo;
    hostExtendInfo.m_osType = hostInfo.m_metadata.m_os_type;
    hostExtendInfo.m_vmIp = "";
    for (int i = 0; i < hostInfo.m_addresses.size(); i++) {
        hostExtendInfo.m_vmIp += hostInfo.m_addresses[i] + ";";
    }
    hostExtendInfo.m_userName = userName;

    if (!Module::JsonHelper::StructToJsonString(hostResource, hostExtendInfo.m_hostResource)) {
        ERRLOG("HostResource format conversion failed.");
        return FAILED;
    }
    std::string hostExtendInfoStr = "";
    if (!Module::JsonHelper::StructToJsonString(hostExtendInfo, hostExtendInfoStr)) {
        ERRLOG("Host info format conversion failed.");
        return FAILED;
    }
    vmDetailInfo.__set_type("CloudHost");
    vmDetailInfo.__set_subType("HCSCloudHost");
    vmDetailInfo.__set_parentId(m_application.id);
    vmDetailInfo.__set_parentName(m_application.name);
    vmDetailInfo.__set_id(hostInfo.m_uuid);
    vmDetailInfo.__set_name(hostInfo.m_name);
    vmDetailInfo.__set_extendInfo(hostExtendInfoStr);

    return SUCCESS;
}

int32_t HcsResourceAccess::GetVolumeResourceList(ResourceResultByPage &page, std::string &parentId)
{
    ProjectResource projectResource;
    if (HostExtendInfoParse(projectResource) != SUCCESS) {
        ERRLOG("Parse HostExtendInfo failed.");
        return FAILED;
    }
    ResourceProjectExtendInfo projectExtendInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectExtendInfo)) {
        ERRLOG("Application info format conversion failed.");
        return FAILED;
    }
    AuthObj auth;
    auth.name = projectResource.m_resourceVdc.m_name;
    auth.passwd = projectResource.m_resourceVdc.m_passwd;
    ShowVolumeListRequest request;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(projectResource.m_resourceVdc.m_domainName);
    request.SetEndpoint(m_appEnv.endpoint);
    request.SetScopeValue(projectExtendInfo.m_projectId);
    request.SetRegion(projectExtendInfo.m_regionId);
    request.SetVolumeStatus(VOLUME_STATUS_IN_USE);
    request.SetVolumeOffset(m_condition.pageNo * m_condition.pageSize);
    request.SetVolumeLimit(m_condition.pageSize);
    parentId = projectExtendInfo.m_projectId;
    EvsClient evsClient;
    std::shared_ptr<ShowVolumeDetailResponse> response = evsClient.ShowVolumeDetailList(request);
    //  若本次接口调用返回403则将缓存清掉进行重试一次
    if (response != nullptr && response->GetStatusCode() == static_cast<uint32_t>(HcsExternalStatusCode::FORIBDDEN)) {
        HCSTokenMgr::GetInstance().DeleteToken(request);
        INFOLOG("Resend request when the response code is 403");
        response = evsClient.ShowVolumeDetailList(request);
    }
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }

    const VolumeDetailList volumeDetail = response->GetHSCVolDetail();
    for (const auto &it : volumeDetail.m_volumeInfo) {
        ApplicationResource vmVolumeDetailInfo;
        if (ComposeVolumeDetail(vmVolumeDetailInfo, it, projectResource.m_resourceVdc.m_name) != SUCCESS) {
            ERRLOG("Compose volume detail failed.volume id:%s, attach point:%d",
                it.m_id.c_str(), it.m_attachPoints.size());
            continue;
        }
        page.items.push_back(vmVolumeDetailInfo);
    }
    page.__set_total(volumeDetail.m_volumeInfo.size());
    DBGLOG("Get virtual machine list success.");
    return SUCCESS;
}

int32_t HcsResourceAccess::ComposeVolumeDetail(ApplicationResource& volumeDetail, const HostVolume& volumeInfo,
    const std::string &userName)
{
    if (volumeInfo.m_attachPoints.empty()) {
        DBGLOG("Volume attach points is empty. no report.");
        return FAILED;
    }

    DiskInfo diskInfo;
    diskInfo.m_id = volumeInfo.m_id;
    diskInfo.m_name = volumeInfo.m_displayName;
    diskInfo.m_mode = volumeInfo.m_bootable;
    diskInfo.m_shareable = volumeInfo.m_shareable;
    diskInfo.m_encrypted = volumeInfo.m_metaData.m_encrypted;
    diskInfo.m_cmkId = volumeInfo.m_metaData.m_cmkId;
    diskInfo.m_cipher = volumeInfo.m_encryptionInfo.m_cipher;
    diskInfo.m_attr = (volumeInfo.m_metaData.m_hwPassthrough == "true") ? "SCSI" : "VBD";
    std::ostringstream os;
    os << volumeInfo.m_size;
    diskInfo.m_size = os.str();
    diskInfo.m_lunWWN = volumeInfo.m_metaData.m_lunWWN;
    diskInfo.m_architecture = volumeInfo.m_volImageMetadata.m_arch;
    OsVolRepDriverData osDriverData;
    if (!Module::JsonHelper::JsonStringToStruct(volumeInfo.m_osVolRepDriverData, osDriverData)) {
        ERRLOG("Get os-volume-replication:driver_data failed.");
        return FAILED;
    }
    diskInfo.m_storageManagerIp = osDriverData.m_ip;
    diskInfo.m_storageType = volumeInfo.m_metaData.m_storageType;

    DiskInfoString diskInfoString;
    if (!Module::JsonHelper::StructToJsonString(diskInfo, diskInfoString.m_diskInfo)) {
        ERRLOG("Disk info format conversion failed.");
        return FAILED;
    }
    diskInfoString.m_userName = userName;
    std::string strDiskInfo;
    if (!Module::JsonHelper::StructToJsonString(diskInfoString, strDiskInfo)) {
        ERRLOG("Disk info string format conversion failed.");
        return FAILED;
    }

    volumeDetail.__set_type("CloudVolume");
    volumeDetail.__set_subType("HCSCloudVolume");
    volumeDetail.__set_parentId(volumeInfo.m_attachPoints[0].m_serverId);
    volumeDetail.__set_parentName("");
    volumeDetail.__set_id(volumeInfo.m_attachPoints[0].m_serverId);
    volumeDetail.__set_name("");
    volumeDetail.__set_extendInfo(strDiskInfo);

    return SUCCESS;
}

int32_t HcsResourceAccess::GetSpcifiedVmInfo(
    ApplicationResource &returnValue, HostResource &hostResource, std::vector<std::string> &vmDiskId)
{
    ProjectResource projectResource;
    if (HostExtendInfoParse(projectResource) != SUCCESS) {
        ERRLOG("Failed to parse host info from task params.");
        return FAILED;
    }
    AuthObj auth;
    auth.name = projectResource.m_resourceVdc.m_name;
    auth.passwd = projectResource.m_resourceVdc.m_passwd;
    GetServerDetailsRequest request;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(projectResource.m_resourceVdc.m_domainName);
    request.SetServerId(hostResource.m_id);
    request.SetEndpoint(m_appEnv.endpoint);
    ResourceProjectExtendInfo projectExtendInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectExtendInfo)) {
        ERRLOG("Application info format conversion failed.");
        return FAILED;
    }
    request.SetScopeValue(projectExtendInfo.m_projectId);
    request.SetRegion(projectExtendInfo.m_regionId);
    DBGLOG("Task params, regionId: %s", projectExtendInfo.m_regionId.c_str());

    EcsClient ecsClient;
    std::shared_ptr<GetServerDetailsResponse> response = ecsClient.GetServerDetails(request);
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return FAILED;
    }
    ServerDetail serverDetail = response->GetServerDetails();
    returnValue.__set_id(serverDetail.m_hostServerInfo.m_uuid);
    returnValue.__set_name(serverDetail.m_hostServerInfo.m_name);
    hostResource.m_status = serverDetail.m_hostServerInfo.m_oSEXTSTSvmState;
    for (const auto &it : serverDetail.m_hostServerInfo.m_osExtendedVolumesvolumesAttached) {
        vmDiskId.push_back(it.m_uuid);
    }
    DBGLOG("Success to get special vm info.");
    return SUCCESS;
}

int32_t HcsResourceAccess::GetSpcifiedEVSDisk(DiskInfo &diskInfo, const std::string &diskId)
{
    ProjectResource projectResource;
    if (HostExtendInfoParse(projectResource) != SUCCESS) {
        ERRLOG("Parse HostExtendInfo failed.");
        return FAILED;
    }
    ResourceProjectExtendInfo projectExtendInfo;
    if (!Module::JsonHelper::JsonStringToStruct(m_application.extendInfo, projectExtendInfo)) {
        ERRLOG("Application info format conversion failed.");
        return FAILED;
    }
    AuthObj auth;
    auth.name = projectResource.m_resourceVdc.m_name;
    auth.passwd = projectResource.m_resourceVdc.m_passwd;
    ShowVolumeRequest request;
    request.SetEnvAddress(m_appEnv.id);
    request.SetUserInfo(auth);
    request.SetDomain(projectResource.m_resourceVdc.m_domainName);
    request.SetVolumeId(diskId);
    request.SetEndpoint(m_appEnv.endpoint);
    request.SetScopeValue(projectExtendInfo.m_projectId);
    request.SetRegion(projectExtendInfo.m_regionId);
    EvsClient evsClient;
    std::shared_ptr<ShowVolumeResponse> response = evsClient.ShowVolumeDetail(request);
    if (response == nullptr || response->GetStatusCode() != static_cast<uint32_t>(HcsExternalStatusCode::OK)) {
        ERRLOG("Failed to get response.");
        return FAILED;
    }
    if (!response->Serial()) {
        ERRLOG("Serial failed.");
        return FAILED;
    }
    diskInfo.m_id = response->GetHSCVolDetail().m_hostVolume.m_id;
    diskInfo.m_name = response->GetHSCVolDetail().m_hostVolume.m_displayName;
    diskInfo.m_mode = response->GetHSCVolDetail().m_hostVolume.m_bootable;
    diskInfo.m_shareable = response->GetHSCVolDetail().m_hostVolume.m_shareable;
    if (response->GetHSCVolDetail().m_hostVolume.m_metaData.m_hwPassthrough == "true") {
        diskInfo.m_attr = "SCSI";
    } else {
        diskInfo.m_attr = "VBD";
    }
    std::ostringstream os;
    os << response->GetHSCVolDetail().m_hostVolume.m_size;
    diskInfo.m_size = os.str();
    diskInfo.m_lunWWN = response->GetHSCVolDetail().m_hostVolume.m_metaData.m_lunWWN;
    diskInfo.m_architecture = response->GetHSCVolDetail().m_hostVolume.m_volImageMetadata.m_arch;
    return SUCCESS;
}

int32_t HcsResourceAccess::HostExtendInfoParse(ProjectResource &projectResource) const
{
    std::string hostVdcInfo = m_application.extendInfo;
    Json::Reader hostInfoReader;
    Json::Value extendVdcInfoJson;
    if (!hostInfoReader.parse(hostVdcInfo, extendVdcInfoJson)) {
        ERRLOG("Failed to read extendInfo.");
        return FAILED;
    }
    if (!extendVdcInfoJson.isMember("project")) {
        ERRLOG("Failed to parse project info from task params.");
        return FAILED;
    }
    std::string project = extendVdcInfoJson["project"].asString();
    if (!Module::JsonHelper::JsonStringToStruct(project, projectResource)) {
        ERRLOG("Host info format conversion failed.");
        return FAILED;
    }
    DBGLOG("Host info format conversion success.");
    return SUCCESS;
}


int32_t HcsResourceAccess::CheckStorageConnect(ApplicationEnvironment &returnEnv)
{
    // 获得存储列表
    std::vector<StorageInfo> storageVector;
    if (!Utils::GetStoragesInfoFromExtendInfo(m_appEnv.auth.extendInfo, storageVector)) {
        ERRLOG("Failed to get storage info from extendinfo.");
        return FAILED;
    }
    if (storageVector.empty()) {
        ERRLOG("No storage info in auth extendinfo!");
        return FAILED;
    }
    // 检验存储连通性
    Json::Value body;
    Json::FastWriter writer;
    bool result = false;
    if (!CheckStorageInfo(storageVector, body, result)) {
        ERRLOG("Check storage resource information failed.");
        returnEnv.__set_extendInfo(writer.write(body));
        return FAILED;
    }

    if (!result) {
        ERRLOG("No storage resource information is available.");
        return FAILED;
    }
    returnEnv.__set_extendInfo(writer.write(body));
    return SUCCESS;
}

bool HcsResourceAccess::CheckStorageInfo(std::vector<StorageInfo> &storageVector, Json::Value &body, bool &result)
{
    int index = 1;
    for (auto &storageInfo : storageVector) {
        ControlDeviceInfo controlDeviceInfo;
        if (!InitControlDeviceInfo(controlDeviceInfo, storageInfo)) {
            ERRLOG("Init control device info failed.");
            return false;
        }

        // 0:集中式  1:分布式
        INFOLOG("Start to check storage connection [NO: %d, ip: %s].", index++, storageInfo.m_ipList.c_str());
        if (storageInfo.m_storageType == STORAGE_TYPE_DISTRIBUTED) {
            INFOLOG("The type of the storage resource is distributed.");
            std::string errorStr;
            if (DistributedStorageMgr::CheckDistributedConnection(controlDeviceInfo, errorStr) == SUCCESS) {
                DBGLOG("Check distributed storage connection success.");
                body[controlDeviceInfo.m_ip] = storageInfo.m_ip;
                result = true;
            } else {
                ERRLOG("Check distributed storage connection failed. errorStr: %s", errorStr.c_str());
                body["errorIp"] = errorStr;
                return false;
            }
            if (!storageInfo.m_vbsIp.empty() && CheckNodeConnect(storageInfo) != SUCCESS) {
                ERRLOG("Check VBS node %s failed. ", storageInfo.m_vbsIp.c_str());
                body["errorIp"] = storageInfo.m_vbsIp;
                return false;
            }
        } else {
            INFOLOG("The type of the storage resource is centralized.");
            StorageSysInfo storageSysInfo;
            std::string errorStr;
            if (StorageMgr::GetStorageSystemInfo(controlDeviceInfo, storageSysInfo, errorStr,
                m_hcsOpServiceUtils.GetIsOpServiceEnv())) {
                DBGLOG("Get storage system info success.");
                DBGLOG("Device id: %s", storageSysInfo.m_id.c_str());
                body[controlDeviceInfo.m_ip] = storageSysInfo.m_id;
                result = true;
            } else {
                ERRLOG("Get storage system info failed. error message: %s, ip: %s",
                    errorStr.c_str(), storageInfo.m_ipList.c_str());
                body["errorIp"] = errorStr;
                return false;
            }
        }
    }
    return true;
}

int32_t HcsResourceAccess::CheckNodeConnect(const StorageInfo& info)
{
    LoginHost cmdExcuter;
    SshParam sshInfo;
    sshInfo.mIp = info.m_vbsIp;
    sshInfo.mUserName = info.m_vbsUserName;
    sshInfo.mPort = info.m_vbsPort;
    sshInfo.mPassWord = info.m_vbsPassWord;
    sshInfo.mCommand = "sudo /bin/vbs_cli";
    std::string resultStr = "";
    if (cmdExcuter.RunCmd(sshInfo, resultStr) != SUCCESS) {
        ERRLOG("Check vbs connect failed, result: %s.", resultStr.c_str());
        return FAILED;
    }
    if (resultStr.find(ERRCODE_VBS_COMMAND_ERR) == std::string::npos) {
        ERRLOG("User %s exec command /bin/vbs_cli failed.", sshInfo.mUserName.c_str());
        return FAILED;
    }
    INFOLOG("Check vbs connect success.");
    return SUCCESS;
}

bool HcsResourceAccess::InitControlDeviceInfo(ControlDeviceInfo &controlDeviceInfo, StorageInfo &storageInfo)
{
    controlDeviceInfo.m_userName = storageInfo.m_userName;
    controlDeviceInfo.m_password = storageInfo.m_passWd;
    controlDeviceInfo.m_ip = storageInfo.m_ip;
    controlDeviceInfo.m_port = std::to_string(storageInfo.m_port);
    controlDeviceInfo.m_storageType = "UnwareType";
    Utils::GetIpVectorFromString(controlDeviceInfo.m_ipList, storageInfo.m_ip, storageInfo.m_ipList);

    controlDeviceInfo.m_enableCert = (storageInfo.m_enableCert == "1") ? true : false;
    std::string storageInfoStr;
    if (!Module::JsonHelper::StructToJsonString(storageInfo, storageInfoStr)) {
        ERRLOG("Convert storageInfo to json string failed.");
        return false;
    }
    CertManger storageCertMgr;
    CertInfo cert;
    if (!storageCertMgr.ParseCert(storageInfo.m_ip, storageInfoStr, cert)) {
        ERRLOG("Parse storage cert info failed.");
        return false;
    }
    if (controlDeviceInfo.m_enableCert) {
        controlDeviceInfo.m_cert = storageCertMgr.GetSpecifyCerPath(storageInfo.m_ip);
    }
    if (!storageInfo.m_revocationList.empty()) {
        controlDeviceInfo.m_revocationList = storageCertMgr.GetSpecifyRclPath(storageInfo.m_ip);
    }
    return true;
}
}  // namespace HcsPlugin